<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Template;

/**
 * ThinkPHP标签库TagLib解析基类
 */
class TagLib {
	
	/**
	 * 标签库定义XML文件
	 * 
	 * @var string
	 * @access protected
	 */
	protected $xml = '';
	protected $tags = array (); // 标签定义
	/**
	 * 标签库名称
	 * 
	 * @var string
	 * @access protected
	 */
	protected $tagLib = '';
	
	/**
	 * 标签库标签列表
	 * 
	 * @var string
	 * @access protected
	 */
	protected $tagList = array ();
	
	/**
	 * 标签库分析数组
	 * 
	 * @var string
	 * @access protected
	 */
	protected $parse = array ();
	
	/**
	 * 标签库是否有效
	 * 
	 * @var string
	 * @access protected
	 */
	protected $valid = false;
	
	/**
	 * 当前模板对象
	 * 
	 * @var object
	 * @access protected
	 */
	protected $tpl;
	protected $comparison = array (
			' nheq ' => ' !== ',
			' heq ' => ' === ',
			' neq ' => ' != ',
			' eq ' => ' == ',
			' egt ' => ' >= ',
			' gt ' => ' > ',
			' elt ' => ' <= ',
			' lt ' => ' < ' 
	);
	
	/**
	 * 架构函数
	 * 
	 * @access public
	 */
	public function __construct() {
		$this->tagLib = strtolower ( substr ( get_class ( $this ), 6 ) );
		$this->tpl = \Think\Think::instance ( 'Think\\Template' );
	}
	
	/**
	 * TagLib标签属性分析 返回标签属性数组
	 * 
	 * @access public
	 * @param string $tagStr
	 *        	标签内容
	 * @return array
	 */
	public function parseXmlAttr($attr, $tag) {
		// XML解析安全过滤
		$attr = str_replace ( '&', '___', $attr );
		$xml = '<tpl><tag ' . $attr . ' /></tpl>';
		$xml = simplexml_load_string ( $xml );
		if (! $xml) {
			E ( L ( '_XML_TAG_ERROR_' ) . ' : ' . $attr );
		}
		$xml = ( array ) ($xml->tag->attributes ());
		if (isset ( $xml ['@attributes'] )) {
			$array = array_change_key_case ( $xml ['@attributes'] );
			if ($array) {
				$tag = strtolower ( $tag );
				if (! isset ( $this->tags [$tag] )) {
					// 检测是否存在别名定义
					foreach ( $this->tags as $key => $val ) {
						if (isset ( $val ['alias'] ) && in_array ( $tag, explode ( ',', $val ['alias'] ) )) {
							$item = $val;
							break;
						}
					}
				} else {
					$item = $this->tags [$tag];
				}
				$attrs = explode ( ',', $item ['attr'] );
				if (isset ( $item ['must'] )) {
					$must = explode ( ',', $item ['must'] );
				} else {
					$must = array ();
				}
				foreach ( $attrs as $name ) {
					if (isset ( $array [$name] )) {
						$array [$name] = str_replace ( '___', '&', $array [$name] );
					} elseif (false !== array_search ( $name, $must )) {
						E ( L ( '_PARAM_ERROR_' ) . ':' . $name );
					}
				}
				return $array;
			}
		} else {
			return array ();
		}
	}
	
	/**
	 * 解析条件表达式
	 * 
	 * @access public
	 * @param string $condition
	 *        	表达式标签内容
	 * @return array
	 */
	public function parseCondition($condition) {
		$condition = str_ireplace ( array_keys ( $this->comparison ), array_values ( $this->comparison ), $condition );
		$condition = preg_replace ( '/\$(\w+):(\w+)\s/is', '$\\1->\\2 ', $condition );
		switch (strtolower ( C ( 'TMPL_VAR_IDENTIFY' ) )) {
			case 'array' : // 识别为数组
				$condition = preg_replace ( '/\$(\w+)\.(\w+)\s/is', '$\\1["\\2"] ', $condition );
				break;
			case 'obj' : // 识别为对象
				$condition = preg_replace ( '/\$(\w+)\.(\w+)\s/is', '$\\1->\\2 ', $condition );
				break;
			default : // 自动判断数组或对象 只支持二维
				$condition = preg_replace ( '/\$(\w+)\.(\w+)\s/is', '(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ', $condition );
		}
		if (false !== strpos ( $condition, '$Think' ))
			$condition = preg_replace_callback ( '/(\$Think.*?)\s/is', array (
					$this,
					'parseThinkVar' 
			), $condition );
		return $condition;
	}
	
	/**
	 * 自动识别构建变量
	 * 
	 * @access public
	 * @param string $name
	 *        	变量描述
	 * @return string
	 */
	public function autoBuildVar($name) {
		if ('Think.' == substr ( $name, 0, 6 )) {
			// 特殊变量
			return $this->parseThinkVar ( $name );
		} elseif (strpos ( $name, '.' )) {
			$vars = explode ( '.', $name );
			$var = array_shift ( $vars );
			switch (strtolower ( C ( 'TMPL_VAR_IDENTIFY' ) )) {
				case 'array' : // 识别为数组
					$name = '$' . $var;
					foreach ( $vars as $key => $val ) {
						if (0 === strpos ( $val, '$' )) {
							$name .= '["{' . $val . '}"]';
						} else {
							$name .= '["' . $val . '"]';
						}
					}
					break;
				case 'obj' : // 识别为对象
					$name = '$' . $var;
					foreach ( $vars as $key => $val )
						$name .= '->' . $val;
					break;
				default : // 自动判断数组或对象 只支持二维
					$name = 'is_array($' . $var . ')?$' . $var . '["' . $vars [0] . '"]:$' . $var . '->' . $vars [0];
			}
		} elseif (strpos ( $name, ':' )) {
			// 额外的对象方式支持
			$name = '$' . str_replace ( ':', '->', $name );
		} elseif (! defined ( $name )) {
			$name = '$' . $name;
		}
		return $name;
	}
	
	/**
	 * 用于标签属性里面的特殊模板变量解析
	 * 格式 以 Think.
	 * 打头的变量属于特殊模板变量
	 * 
	 * @access public
	 * @param string $varStr
	 *        	变量字符串
	 * @return string
	 */
	public function parseThinkVar($varStr) {
		if (is_array ( $varStr )) { // 用于正则替换回调函数
			$varStr = $varStr [1];
		}
		$vars = explode ( '.', $varStr );
		$vars [1] = strtoupper ( trim ( $vars [1] ) );
		$parseStr = '';
		if (count ( $vars ) >= 3) {
			$vars [2] = trim ( $vars [2] );
			switch ($vars [1]) {
				case 'SERVER' :
					$parseStr = '$_SERVER[\'' . $vars [2] . '\']';
					break;
				case 'GET' :
					$parseStr = '$_GET[\'' . $vars [2] . '\']';
					break;
				case 'POST' :
					$parseStr = '$_POST[\'' . $vars [2] . '\']';
					break;
				case 'COOKIE' :
					if (isset ( $vars [3] )) {
						$parseStr = '$_COOKIE[\'' . $vars [2] . '\'][\'' . $vars [3] . '\']';
					} elseif (C ( 'COOKIE_PREFIX' )) {
						$parseStr = '$_COOKIE[\'' . C ( 'COOKIE_PREFIX' ) . $vars [2] . '\']';
					} else {
						$parseStr = '$_COOKIE[\'' . $vars [2] . '\']';
					}
					break;
				case 'SESSION' :
					if (isset ( $vars [3] )) {
						$parseStr = '$_SESSION[\'' . $vars [2] . '\'][\'' . $vars [3] . '\']';
					} elseif (C ( 'SESSION_PREFIX' )) {
						$parseStr = '$_SESSION[\'' . C ( 'SESSION_PREFIX' ) . '\'][\'' . $vars [2] . '\']';
					} else {
						$parseStr = '$_SESSION[\'' . $vars [2] . '\']';
					}
					break;
				case 'ENV' :
					$parseStr = '$_ENV[\'' . $vars [2] . '\']';
					break;
				case 'REQUEST' :
					$parseStr = '$_REQUEST[\'' . $vars [2] . '\']';
					break;
				case 'CONST' :
					$parseStr = strtoupper ( $vars [2] );
					break;
				case 'LANG' :
					$parseStr = 'L("' . $vars [2] . '")';
					break;
				case 'CONFIG' :
					$parseStr = 'C("' . $vars [2] . '")';
					break;
			}
		} else if (count ( $vars ) == 2) {
			switch ($vars [1]) {
				case 'NOW' :
					$parseStr = "date('Y-m-d g:i a',time())";
					break;
				case 'VERSION' :
					$parseStr = 'THINK_VERSION';
					break;
				case 'TEMPLATE' :
					$parseStr = 'C("TEMPLATE_NAME")';
					break;
				case 'LDELIM' :
					$parseStr = 'C("TMPL_L_DELIM")';
					break;
				case 'RDELIM' :
					$parseStr = 'C("TMPL_R_DELIM")';
					break;
				default :
					if (defined ( $vars [1] ))
						$parseStr = $vars [1];
			}
		}
		return $parseStr;
	}
	
	// 获取标签定义
	public function getTags() {
		return $this->tags;
	}
}